/*
 * @Descripttion: 
 * @Author: yubo
 * @Date: 2022-08-30 17:28:15
 * @LastEditTime: 2022-08-30 17:34:30
 */
#include "rsa.h"

#include <fstream>

using namespace std;

std::vector<std::mutex> rsa::vectorOfSslMutex(CRYPTO_num_locks());

//----------------------------------------
auto rsa::locking_function(int mode,
	int n,
	const char * file,
	int line
	) -> void
	//----------------------------------------
{
	if (mode & CRYPTO_LOCK)   vectorOfSslMutex[n].lock();
	else                        vectorOfSslMutex[n].unlock();
}


string rsa::encrypt(const std::string &clear, const std::string &public_key)
{
	BIO* b = BIO_new_mem_buf(public_key.c_str(), -1);
	if (b == NULL) {
		throw runtime_error("read public key fail");
	}

	RSA* rsa = PEM_read_bio_RSA_PUBKEY(b, NULL, NULL, NULL);
	BIO_free_all(b);
	if (rsa == NULL){
		throw runtime_error("read public key fail");
	}

	// create buffer
	string cipher;
	cipher.resize(RSA_size(rsa));

	// encrypt
	int ret = RSA_public_encrypt(clear.length(), (unsigned char*)clear.c_str(), (unsigned char*)cipher.data(), rsa, RSA_PKCS1_PADDING);
	RSA_free(rsa);
	if (ret < 0)
	{
		throw runtime_error("rsa encrypt fail");
	}

	return cipher;
}

string rsa::decrypt(const std::string &cipher, const std::string &pirvate_key)
{
	BIO* b = BIO_new_mem_buf(pirvate_key.c_str(), -1);
	if (b == NULL) {
		throw runtime_error("read private key fail");
	}
	BIO_free_all(b);

	// create rsa
	RSA* rsa = PEM_read_bio_RSAPrivateKey(b, NULL, NULL, NULL);

	// create buffer
	string clear;
	clear.resize(RSA_size(rsa));

	//ofstream off("d:\\enc.txt", ios::binary);
	//off << clear;

	int clear_len = RSA_private_decrypt(cipher.length(), (const unsigned char*)cipher.c_str(), (unsigned char*)clear.data(), rsa, RSA_PKCS1_PADDING);
	RSA_free(rsa);
	if (clear_len < 0)
	{
		throw runtime_error("rsa decrypt fail");
	}

	return clear.substr(0, clear_len);
}